#include "uart_utils.h"
#include "mem_utils.h"

#include "usart.h"

#include "FreeRTOS.h"
#include "queue.h"


#if defined(STM32F407_UART)

// f407 function
static char stm32f407_uart_init(struct uart_device *dev, int baud, int data_bits, int stop_bits, int parity);
static char stm32f407_uart_send(struct uart_device *dev, unsigned char *data, unsigned int len, unsigned int timeout);
static char stm32f407_uart_recv(struct uart_device *dev, unsigned char *data, unsigned int timeout);

// special device private data
struct priv_struct g_f407_priv = {
	&huart1,
};

// special device
struct uart_device dev_f407 = {
	"f407_uart1",
	stm32f407_uart_init,
	stm32f407_uart_send,
	stm32f407_uart_recv,
	(struct priv_struct*)&g_f407_priv,
};



void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
	struct priv_struct *tdata;
      
	if (huart == tdata->xUart)
	{
		tdata = dev_f407.priv;
		/* notify TX complete */
		xSemaphoreGiveFromISR(tdata->xMutex, NULL);
	}
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	struct priv_struct *tdata;
	
	tdata = dev_f407.priv;
	
	// put data into queue
	xQueueSendFromISR(tdata->xQueue, &tdata->pdata, NULL);
	
	// trigger the next data on the same UART
	HAL_UART_Receive_IT(tdata->xUart, &tdata->pdata, 1);
}



static char stm32f407_uart_init(struct uart_device *dev, int baud, int data_bits, int stop_bits, int parity)
{
	struct priv_struct *tdata = dev->priv;
	
	tdata->xMutex = xSemaphoreCreateMutex();
	tdata->xQueue = xQueueCreate(20, 1);
	
	// start uart recv
	HAL_UART_Receive_IT(&huart1, &tdata->pdata, 1);
	
	return 0;
}

static char stm32f407_uart_send(struct uart_device *dev, unsigned char *data, unsigned int len, unsigned int timeout)
{
	struct priv_struct *tdata = dev->priv;
	
	// trigger transmit interrupt
	HAL_UART_Transmit(tdata->xUart, data, len, timeout);
	
	// wait mutex
	if(pdPASS == xSemaphoreTake(tdata->xMutex, timeout))
		return 0;
	else
		return 1;
}

static char stm32f407_uart_recv(struct uart_device *dev, unsigned char *data, unsigned int timeout)
{
	struct priv_struct *tdata = dev->priv;

	// get data from queue
	if(pdPASS == xQueueReceive(tdata->xQueue, data, timeout))
		return 0;
	else
		return 1;
}

#endif







// global device array
struct uart_device* g_dev[] = {
	&dev_f407,
};



/**
 * find uart device by name
 * 
 * @param name the name of the uart device
 * 
 * @return the uart device
 */
struct uart_device * find_dev_by_name(char *name)
{
	for(int i = 0; i < sizeof(g_dev) / sizeof(g_dev[0]); i++)
	{
		if(mymemcmp(g_dev[i]->name, name, sizeof(g_dev[i]->name)) == 0)
		{
			return g_dev[i];
		}
	}

	return (struct uart_device *)0xFFFFFFFF;
}

